package com.gitee.wsl.transform.converter.case

import com.gitee.wsl.transform.split.WordSplitter
import com.gitee.wsl.transform.split.WordSplitterConfig
import com.gitee.wsl.transform.split.WordSplitterConfigurable


/**
 * An enumeration that contains a standard set of [CaseFormatter]s.
 */
enum class CaseFormat(caseFormatterConfig: CaseFormatterConfig, wordSplitterConfig: WordSplitterConfig) : CaseFormatter by CaseFormatterConfigurable(caseFormatterConfig), WordSplitter by WordSplitterConfigurable(wordSplitterConfig) {
    /** SCREAMING_SNAKE_CASE */
    UPPER_UNDERSCORE(CaseFormatterConfig(true, "_"), WordSplitterConfig(setOf('_'))),
    /** snake_case */
    LOWER_UNDERSCORE(CaseFormatterConfig(false, "_"), WordSplitterConfig(setOf('_'))),
    /** PascalCase */
    CAPITALIZED_CAMEL(CaseFormatterConfig(false, wordCapitalize = true, firstWordCapitalize = true), WordSplitterConfig(setOf(' ', '-', '_', '.'), handleCase = true, treatDigitsAsUppercase = true)),
    /** camelCase */
    CAMEL(CaseFormatterConfig(false, wordCapitalize = true, firstWordCapitalize = false), WordSplitterConfig(setOf(' ', '-', '_', '.'), handleCase = true, treatDigitsAsUppercase = true)),
    /** TRAIN-CASE */
    UPPER_HYPHEN(CaseFormatterConfig(true, "-"), WordSplitterConfig(setOf('-'))),
    /** kebab-case */
    LOWER_HYPHEN(CaseFormatterConfig(false, "-"), WordSplitterConfig(setOf('-'))),
    /** UPPER SPACE CASE */
    UPPER_SPACE(CaseFormatterConfig(true, " "), WordSplitterConfig(setOf(' '))),
    /** Title Case */
    CAPITALIZED_SPACE(CaseFormatterConfig(false, " ", wordCapitalize = true, firstWordCapitalize = true), WordSplitterConfig(setOf(' '))),
    /** Sentence case */
    SENTENCE_SPACE(CaseFormatterConfig(false, " ", wordCapitalize = false, firstWordCapitalize = true), WordSplitterConfig(setOf(' '))),
    /** lower space case */
    LOWER_SPACE(CaseFormatterConfig(false, " "), WordSplitterConfig(setOf(' '))),
    /** UPPER.DOT.CASE */
    UPPER_DOT(CaseFormatterConfig(true, "."), WordSplitterConfig(setOf('.'))),
    /** dot.case */
    LOWER_DOT(CaseFormatterConfig(false, "."), WordSplitterConfig(setOf('.')));
}

private fun createUniversalWordSplitter(treatDigitsAsUppercase: Boolean): WordSplitter {
    return WordSplitterConfigurable(WordSplitterConfig(
        boundaries = setOf(' ', '-', '_', '.'),
        handleCase = true,
        treatDigitsAsUppercase = treatDigitsAsUppercase
    ))
}


private val UNIVERSAL_WORD_SPLITTER_DIGITS_UPPERCASE = createUniversalWordSplitter(true)

private val UNIVERSAL_WORD_SPLITTER_DIGITS_NOT_UPPERCASE = createUniversalWordSplitter(false)

/**
 * Returns a default [WordSplitter] that can be used to split a string in any supported case format into words.
 * However, its behavior may be strange and it's always better to specify other [WordSplitter] (for example one of [CaseFormat]s) manually.
 * @param treatDigitsAsUppercase See [WordSplitterConfig.treatDigitsAsUppercase]
 */
fun universalWordSplitter(treatDigitsAsUppercase: Boolean = true) =  if(treatDigitsAsUppercase) UNIVERSAL_WORD_SPLITTER_DIGITS_UPPERCASE else UNIVERSAL_WORD_SPLITTER_DIGITS_NOT_UPPERCASE

/**
 * Returns a copy of this string converted to another case by splitting it into multiple words using [specified][from] [WordSplitter] and joining them using [specified][to] [CaseFormatter].
 */
fun String.toCase(to: CaseFormatter, from: WordSplitter = universalWordSplitter()) = to.format(this, from)

/**
 * Returns a copy of this string converted to another case by splitting it into multiple words using [specified][from] [WordSplitter] and joining them using [CaseFormatterConfigurable] configured with [toConfig].
 */
fun String.toCase(toConfig: CaseFormatterConfig, from: WordSplitter = universalWordSplitter()) = toCase(CaseFormatterConfigurable(toConfig), from)

/**
 * Returns a copy of this string converted to another case by splitting it into multiple words using [WordSplitterConfigurable] configured with [fromConfig] and joining them using [CaseFormatterConfigurable] configured with [toConfig].
 */
fun String.toCase(toConfig: CaseFormatterConfig, fromConfig: WordSplitterConfig) = toCase(toConfig, WordSplitterConfigurable(fromConfig))

/** Returns a copy of this string converted to SCREAMING_SNAKE_CASE by splitting it into multiple words using [specified][from] [WordSplitter] and joining them using [CaseFormat.UPPER_UNDERSCORE]. */
fun String.toScreamingSnakeCase(from: WordSplitter = universalWordSplitter()) = toCase(CaseFormat.UPPER_UNDERSCORE, from)

/** Returns a copy of this string converted to snake_case by splitting it into multiple words using [specified][from] [WordSplitter] and joining them using [CaseFormat.LOWER_UNDERSCORE].. */
fun String.toSnakeCase(from: WordSplitter = universalWordSplitter()) = toCase(CaseFormat.LOWER_UNDERSCORE, from)

/** Returns a copy of this string converted to PascalCase by splitting it into multiple words using [specified][from] [WordSplitter] and joining them using [CaseFormat.CAPITALIZED_CAMEL].. */
fun String.toPascalCase(from: WordSplitter = universalWordSplitter()) = toCase(CaseFormat.CAPITALIZED_CAMEL, from)

/** Returns a copy of this string converted to camelCase by splitting it into multiple words using [specified][from] [WordSplitter] and joining them using [CaseFormat.CAMEL].. */
fun String.toCamelCase(from: WordSplitter = universalWordSplitter()) = toCase(CaseFormat.CAMEL, from)

/** Returns a copy of this string converted to TRAIN-CASE by splitting it into multiple words using [specified][from] [WordSplitter] and joining them using [CaseFormat.UPPER_HYPHEN].. */
fun String.toTrainCase(from: WordSplitter = universalWordSplitter()) = toCase(CaseFormat.UPPER_HYPHEN, from)

/** Returns a copy of this string converted to kebab-case by splitting it into multiple words using [specified][from] [WordSplitter] and joining them using [CaseFormat.LOWER_HYPHEN].. */
fun String.toKebabCase(from: WordSplitter = universalWordSplitter()) = toCase(CaseFormat.LOWER_HYPHEN, from)

/** Returns a copy of this string converted to UPPER SPACE CASE by splitting it into multiple words using [specified][from] [WordSplitter] and joining them using [CaseFormat.UPPER_SPACE].. */
fun String.toUpperSpaceCase(from: WordSplitter = universalWordSplitter()) = toCase(CaseFormat.UPPER_SPACE, from)

/** Returns a copy of this string converted to Title Case by splitting it into multiple words using [specified][from] [WordSplitter] and joining them using [CaseFormat.CAPITALIZED_SPACE].. */
fun String.toTitleCase(from: WordSplitter = universalWordSplitter()) = toCase(CaseFormat.CAPITALIZED_SPACE, from)

/** Returns a copy of this string converted to Sentence case by splitting it into multiple words using [specified][from] [WordSplitter] and joining them using [CaseFormat.SENTENCE_SPACE].. */
fun String.toSentenceCase(from: WordSplitter = universalWordSplitter()) = toCase(CaseFormat.SENTENCE_SPACE, from)

/** Returns a copy of this string converted to lower space case by splitting it into multiple words using [specified][from] [WordSplitter] and joining them using [CaseFormat.LOWER_SPACE].. */
fun String.toLowerSpaceCase(from: WordSplitter = universalWordSplitter()) = toCase(CaseFormat.LOWER_SPACE, from)

/** Returns a copy of this string converted to UPPER.DOT.CASE by splitting it into multiple words using [specified][from] [WordSplitter] and joining them using [CaseFormat.UPPER_DOT].. */
fun String.toUpperDotCase(from: WordSplitter = universalWordSplitter()) = toCase(CaseFormat.UPPER_DOT, from)

/** Returns a copy of this string converted to dot.case by splitting it into multiple words using [specified][from] [WordSplitter] and joining them using [CaseFormat.LOWER_DOT].. */
fun String.toDotCase(from: WordSplitter = universalWordSplitter()) = toCase(CaseFormat.LOWER_DOT, from)
